package com.hliushi.learn.service.impl;

import com.hliushi.learn.bean.Reader;
import com.hliushi.learn.dao.ReaderDao;
import com.hliushi.learn.listener.MyEvent;
import com.hliushi.learn.service.ReaderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.sql.SQLException;
import java.util.List;

/**
 * @ClassName ReaderServiceImpl
 * @Description TODO
 * @Author liushi
 * @Date 2021/7/8 9:59
 * @Version V1.0
 **/
@Service
public class ReaderServiceImpl implements ReaderService {

    @Autowired
    private ReaderDao readerDao;

    @Resource
    private ApplicationContext applicationContext;


    @Override
    public Reader getReaderById(Integer readerId) {
        return readerDao.getReaderById(readerId);
    }

    @Override
    public List<Reader> getReaderAll() {
        return readerDao.getReaderAll();
    }

    /**
     * 测试一下Springboot中的事务处理, 在Service层, 我们手动抛出个异常来模拟实际中出现的异常
     * 然后观察一下事务有没有回滚, 如果数据库中没有新的记录, 则说明事务回滚成功
     *
     * @param reader
     */
    @Override
    @Transactional
    public void insertReader(Reader reader) {
        // 插入读者信息
        readerDao.insertReader(reader);

        // 手动抛出异常   java.lang.RuntimeException: null
        /**
         * RuntimeException类以及其子类异常 属于  UncheckedException异常
         * 这写异常是不检查异常, 程序中可以选择捕获异常, 也可以不处理,
         * 这些异常一般是有程序逻辑错误引起的, 程序应该从逻辑角度尽可能避免这类异常的发生
         * #
         * 运行时异常的特点是Java编译器不会检测它, 也就说, 当程序中可能出现这类异常,
         * 即使没有用try/catch语句捕获它, 也没有用throws语句抛出它, 也会编译通过
         *
         * #
         * 与此对应的是 CheckException 检查异常 非运行时异常
         * 可查异常即 必须进行处理的异常, 要么try/catch主, 要么往外抛, 谁调用, 谁处理
         * 比如FileNotFoundException, SqlException, 如果不处理, 程序就不能编译通过
         */
        throw new RuntimeException();
    }


    /**
     * 测试异常并没有被 "捕获" 到
     * #
     * 就是异常并没有被"捕获"到, 导致事务并没有回滚
     * 原因: Springboot默认的事务规则是遇到 RuntimeException 和程序错误(Error) 才会回滚
     * 但是遇到 Exception类以及其子类 非运行时异常, 默认是不会滚事务的
     * 如果进行回滚的话, 在@Transaction注解中使用rollbackFor属性来指定异常
     * 比如@Transactional(rollbackFor = Exception.class), 这样就没问题了, 所有在实际项目中, 一定要指定异常
     *
     * @param reader
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    // @Transactional
    public void insertReader2(Reader reader) throws SQLException {
        // 插入读者信息
        readerDao.insertReader(reader);

        // 手动抛出异常
        throw new SQLException();
    }


    /**
     * 测试异常被 "吃"掉
     * #
     * 我们处理异常时, 有两种方式, 要么抛出去, 让上一层来捕获处理
     * 要么把异常try/catch掉, 在异常出现的地方给处理掉,
     * 就因为有这个try/catch, 所以导致异常被"吃"掉, 事务无法回滚
     * #
     * 这种问题, 直接往上抛, 给上一层俩处理即可, 千万不要在事务汇总把异常自己 "吃"掉
     *
     * @param reader
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void insertReader3(Reader reader) {
        try {
            // 插入读者信息
            readerDao.insertReader(reader);

            // 手动抛出异常
            throw new SQLException("数据库异常!");
        } catch (Exception e) {
            // e.printStackTrace();
            // 异常处理逻辑
        }
    }

    /**
     * 获取用户信息
     *
     * @return reader
     */
    @Override
    public Reader getMyReader() {
        // 实际中会根据集体的业务场景, 从数据库中查询对应的信息
        return new Reader(10001, "hliushi", "男", null, "安徽省六安市", "13083071070");
    }


    /**
     * 发布事件
     *
     * @return
     */
    @Override
    public Reader getMyReader2() {
        Reader reader = new Reader(10001, "hliushi", "男", null, "安徽省六安市", "13083071070");
        MyEvent event = new MyEvent(this, reader);
        applicationContext.publishEvent(event);
        return reader;
    }


    public void method() {


    }

}
